require "Common/define"
require "Logic/Config"
require "Common/functions"
require "Logic/StrangeFragmentManager"

---@class ItemManager
ItemManager = {};
local this = ItemManager;
local itemCfg = nil;
local equipCfg = nil;
---@type ClientItemData[]
local tabAllItem = {};
---@type ClientItemData[]
local currencyTable = {}; --货币
local tabUseBackItem = {};
this.constFavorItemDatas={}
function ItemManager.init()
    itemCfg = G.dataTable["t_item"];
    equipCfg = dataTable.getDataTable("t_equip");
    StrangeFragmentManager.Init()
    this.itemDataPool = {}
end
---@return ClientItemData
function ItemManager.GetFromPool()
    if #this.itemDataPool > 0 then

        return table.remove(this.itemDataPool)
    end
    return ClientItemData.New(0,0,0)
end
---@param item ClientItemData
function ItemManager.ReturnToPool(item)
    if not item then return end
    if #this.itemDataPool > 100 then
        return
    end
    item:Set(0,0,0)
    table.insert(this.itemDataPool,item)
end
--通过页签类型获取道具数据
--bagSplit 背包中堆叠上限拆分
function ItemManager.getItemDataByTabType(tabType,bagSplit)
    local list = {};
    local bagIndex = 1
    for k,v in pairs(tabAllItem) do
        if v.tabType == tabType then
            if v.itemType ~= EnumConst.ItemTypeEnum.TimeBox and v.itemType~=9 then --暂时不入背包
                if bagSplit then
                    bagIndex = this.GetBagSplitItemList(v,list,bagIndex)
                else
                    table.insert(list,v)
                end
            end
        end
    end
    for k, v in pairs(currencyTable) do
        if tabType == EnumConst.ItemTableEnum.Item and v.itemBag == 1 and v.num > 0 then
            if bagSplit then
                bagIndex = this.GetBagSplitItemList(v,list,bagIndex)
            else
                table.insert(list, v);
            end

        end
    end
    return list;
end
--堆叠分割
---@param source ClientItemData
function ItemManager.GetBagSplitItemList(source,list,bagStartId)
    local count = tonumber(tostring(source.num))
    local limit = dataTable.getDataTableByStringId("t_item",source.itemModelId,"f_Add")
    while(count > 0) do
        local item = this.GetFromPool()
        if count > limit and limit > 0 then
            item:Set(source.itemId,source.itemModelId,limit,true)
        else
            item:Set(source.itemId,source.itemModelId,count,true)
        end
        item:SetBagId(bagStartId)
        table.insert(list, item);
        bagStartId = bagStartId + 1
        if limit == 0 then
            count = 0
        else
            count  = count - limit
        end
    end
    return bagStartId
end
--通过物品类型获取道具数据
function ItemManager.getItemDatabyItemType(itemType,list,ignoreClone)
    list = list or {};
    for k,v in pairs(tabAllItem) do
        if v.itemType == itemType then
            if ignoreClone then
                table.insert(list, v);
            else
                table.insert(list, clone(v));
            end
        end
    end
    return list;
end
function ItemManager.GetRefineMatList(includeEx)
    local list = {}
    for k,v in pairs(tabAllItem) do
        if v.itemType == EnumConst.ItemTypeEnum.Refine then
            if includeEx then
                table.insert(list, v);
            elseif v.itemModelId == 200011 or v.itemModelId == 200012 then--尼玛
                table.insert(list,v)
            end
        end
    end
    return list;
end
--通过物品类型获取道具数据
function ItemManager.getItemCountbyItemTypeAndItemModelId( itemType, item_model_id ) 
    local count = 0 
    for k,v in pairs(tabAllItem) do 
        if v.tabType == itemType then 
            if item_model_id and v and tonumber(v.itemModelId) == tonumber(item_model_id) then
                count = count + tonumber(v.num)
            end 
        end
    end
    for k, v in pairs(currencyTable) do 
        if itemType == EnumConst.ItemTableEnum.Item and v.itemBag == 1 then 
            if item_model_id and v and tonumber(v.itemModelId) == tonumber(item_model_id) then
                count = count + tonumber(v.num)
            end
        end
    end
    return count
end

--添加物品
function ItemManager.addItemData(itemDB,sourceCode,params,bagType)
    local _lastCount = 0
    local _itemId = tostring(itemDB.itemId)
    local itemData = tabAllItem[_itemId]
    if itemData then
        _lastCount = itemData.num
        itemData:SetNum(itemDB.num)
    else
        itemData = this.GetFromPool()
        itemData:Set(itemDB.itemId,itemDB.itemModelId,itemDB.num,true)
        itemData:SetTabType(bagType)
    end
    if itemData.isInvalid then
        this.ReturnToPool(itemData)
        return
    end
    tabAllItem[_itemId] = itemData
    TAManager.TrackItemEvent(itemData["itemId"],itemData["itemModelId"],itemData["num"],_lastCount,sourceCode,params)
end

--删除物品
function ItemManager.delItemData(itemId,sourceCode,params)
    itemId = tostring(itemId)
    local item = tabAllItem[itemId]
    if item then
        TAManager.TrackItemEvent(item["itemId"],item["itemModelId"],0,item["num"],sourceCode,params)
        this.ReturnToPool(item)
        tabAllItem[itemId] = nil
    end
end

--获取物品页签类型
function ItemManager.getItemTabType(itemModelId)
    local modelId = tonumber(itemModelId);
    local type = math.floor(modelId / 100000);
    return type
    --[[if type == EnumConst.ItemTableEnum.Currency then
        return EnumConst.ItemTableEnum.Currency;
    elseif type == EnumConst.ItemTableEnum.Equip then
        return EnumConst.ItemTableEnum.Equip;
    elseif type == EnumConst.ItemTableEnum.Item then
        return EnumConst.ItemTableEnum.Item;
    elseif type == EnumConst.ItemTableEnum.Hero then
        return EnumConst.ItemTableEnum.Hero;
    elseif type == EnumConst.ItemTableEnum.Fragment then
        return EnumConst.ItemTableEnum.Fragment;
    end]]
end
function ItemManager.IsTimeBoxKeyAndEnoughOpen(modelId)
    if modelId == nil then return false end
    local keyCount = logicMgr.ItemManager.getItemCountbyModelId(modelId)
    local cfg = dataTable.getDataTableByStringId("t_item",modelId)
    if not cfg or cfg.f_BagType ~= EnumConst.ItemTypeEnum.TimeBoxKey then return false end
    local func = decodeJsonStrToTabel(cfg.f_ItemFunction)
    local boxCfg = dataTable.getDataTableByStringId("t_item",func[1])
    if not boxCfg then return false end
    local boxCount = logicMgr.ItemManager.GetItemTimeBoxCount(boxCfg.f_itemModelId,true)
    return true,keyCount > 0 and boxCount > 0
end
--获取物品信息
function ItemManager.getItemData(itemId)
    itemId = tostring(itemId)
    return tabAllItem[itemId]
end
function ItemManager.GetItemName(itemModelId)
    local item = itemCfg[tostring(itemModelId)];
    if item ~= nil then
        return getLanguage(item.f_ItemName);
    end
    return ""
end
function ItemManager.GetItemQuality(itemModelId)
    local item = itemCfg[tostring(itemModelId)];
    if item ~= nil then
        return item.f_Quality;
    end
    return 1
end
function ItemManager.GetItemIcon(itemModelId)
    local item = itemCfg[tostring(itemModelId)];
    if item ~= nil then
        return item.f_Icon;
    end
    return ""
end
function ItemManager.GetItemIconPath(itemModelId)
    local item = itemCfg[tostring(itemModelId)];
    if item ~= nil then
        return EnumConst.AtlasPath.ItemAtlas ..item.f_Icon;
    end
    return ""
end
function ItemManager.GetItemDesc(itemModelId)
    local item = itemCfg[tostring(itemModelId)];
    if item ~= nil then
        return getLanguage(item.f_Desc);
    end
    return ""
end
function ItemManager.GetItemConsumptionPoints(itemModelId)
    local item = itemCfg[tostring(itemModelId)];
    if item ~= nil then
        return item.f_ConsumptionPoints;
    end
    return 0
end
function ItemManager.GetQualityFramePath(quality)
    return EnumConst.AtlasPath.ICONAtlas .. Config.IconFrame[tonumber(quality)]
end
function ItemManager.GetQualityBGPath(quality)
    return EnumConst.AtlasPath.ICONAtlas .. Config.IconQuality[tonumber(quality)]
end

--获取同类型物品数量
function ItemManager.getItemCountbyModelId(itemModelId)
    if itemModelId == nil then
        return 0
    end
    itemModelId = tonumber(itemModelId)
    for k,v in pairs(tabAllItem) do
        if v.itemModelId == itemModelId then
            return v.num
        end
    end
    return 0;
end
--时光魔晶数量（是否包含序列中的个数
function ItemManager.GetItemTimeBoxCount(itemModelId,includeGrid)
    local count = this.getItemCountbyModelId(itemModelId)
    if includeGrid then
        count = count + TimeBoxHandler.GetBoxCountExcludeAwardByModelId(itemModelId)
    end
    return count
end

function ItemManager.getItemIdByModelId(itemModelId)
    itemModelId = tonumber(itemModelId)
    for k,v in pairs(tabAllItem) do
        if v.itemModelId == itemModelId then
            return v.itemId
        end
    end
    return nil
end
--获取物品静态数据
function ItemManager.getItemConstDatabyModelId(itemModelId, hasBagNum)
    local item = itemCfg[tostring(itemModelId)];
    if item ~= nil then
        --local itemData = this.GetFromPool()
        --itemData:Set(0,itemModelId,nil,true)
        local itemData = {}
        itemData["name"] = getLanguage(item.f_ItemName);
        itemData["itemType"] = item.f_BagType;
        itemData["quality"] = item.f_Quality;
        itemData["icon"] = item.f_Icon;
        itemData["desc"] = getLanguage(item.f_Desc);
        itemData["itemFunction"] = item.f_ItemFunction;
        itemData["itemModelId"] = item.f_itemModelId
        itemData["scriptId"] = item.f_ScriptId;
        itemData["cornerMark"] = item.f_CornerMark
        itemData["cornerMarkRight"] = item.f_CornerMarkRight
        if hasBagNum then
            itemData.num = ItemManager.getBagNumByTableID(itemModelId);
            --itemData:SetNum(ItemManager.getBagNumByTableID(itemModelId))
        end
        return itemData;
    end
    return nil;
end

--更新物品数量
function ItemManager.setItemData(itemId, num,sourceCode,params)
    itemId = tostring(itemId)
    local item = tabAllItem[itemId]
    if not item then return end
    local _newNumber = num
    local _lastCount = tonumber(item.num)
    item:SetNum(_newNumber)
    --道具变更埋点
    TAManager.TrackItemEvent(item.itemId,item.itemModelId,_newNumber,_lastCount,sourceCode,params)
    if _lastCount >_newNumber then
        AudioManager.TryPlaySoundItemChange(toNumber(item.itemModelId),false)
    end
end

---获取货币类道具的数量
function ItemManager.getCurrencyCountByModelId(currencyModelId)
    local data = currencyTable[currencyModelId]
    if data ~= nil then
        return data.num;
    end
    return 0;
end

---通过tableID获得总数量
-- tableID:对应t_item中的f_itemModelId
function ItemManager.getBagNumByTableID(tableID)
    local itemType = this.getItemTabType(tableID)
    if itemType == EnumConst.ItemTableEnum.Currency then
        if tableID == CurrencyEnum.FriendGiftBoxPoint then
            return logicMgr.FriendManager.friendGiftPoint
        end
        return this.getCurrencyCountByModelId(tonumber(tableID))
    else
        return this.getItemCountbyModelId(tableID)
    end
end

---设置货币类道具的数量
function ItemManager.setCurrencyCount(currencyModelId, count,sourceCode,params)
    local data = currencyTable[currencyModelId]
    if data == nil then
        data = this.GetFromPool()
        data:Set(currencyModelId,currencyModelId,count,true)
        if data.isInvalid then
            this.ReturnToPool(data)
            return
        end
        currencyTable[currencyModelId] = data;
    end
    local _previousCount = data.num
    if _previousCount == nil then
        _previousCount = 0
    end
    if _previousCount > tonumber(count) then
        AudioManager.TryPlaySoundItemChange(currencyModelId,false)
    end
    TAManager.TrackItemEvent(-1,currencyModelId,count,_previousCount,sourceCode,params)
    data:SetNum(count)
    if currencyModelId == CurrencyEnum.RoleExp then
        --更新主角经验信息
        G.serverData["roleInfo"].show["exp"] = count
    end
    if currencyModelId == CurrencyEnum.GOLD then
        FireEvent(Config.EventType.CURRENCY_RefreshDiamondNum)
        log("当前用户红魔石数量: "..count);
    end
end

function ItemManager.resUseItemBack(itemData)
    TablePool.Release(tabUseBackItem)
    tabUseBackItem = TablePool.Get()
    local rewardItems = itemData["rewardItems"];
    local isChangeToChips = false;  --判断是否已拥有英雄转化成碎片
    local dropConfig = G.dataTable["t_drop"];
    local haveChips = false;
    for i = 1, #rewardItems do
        local id = tostring(rewardItems[i].itemModelId);
        local cfg = dataTable.getRow("t_item", id);
        if cfg and cfg.f_BagType == EnumConst.ItemTypeEnum.Hero then
            haveChips = true;
        end
        local item = tabUseBackItem[id]
        if not item then
            item = TablePool.Get()
            item["itemModelId"] = id
            item["num"] = tonumber(tostring(rewardItems[i].num));
            item["isbind"] = rewardItems[i].isbind;
            item["ltime"] = rewardItems[i].ltime;
            --item["ldate"] = rewardItems[i].ldate;
            item["parameters"] = rewardItems[i].parameters;
            if this.IsEquip(item["itemModelId"]) then
                item["icon"] = equipCfg[item["itemModelId"]].f_EquipIcon;
                item["quality"] = equipCfg[item["itemModelId"]].f_EquipQuality;
            else
                item["icon"] = itemCfg[item["itemModelId"]].f_Icon;
                item["quality"] = itemCfg[item["itemModelId"]].f_Quality;
            end
        else
            item.num = item.num + tonumber(tostring(rewardItems[i].num))
        end
        tabUseBackItem[id] = item
    end
    if itemData["itemModelId"] == 200035 then
        UISysTips.AddMsg(getLanguage("ErrorCode_220003"))
    end
    if haveChips then
        local rowInfo = nil
        for _,v in pairs(dropConfig) do
            if v.f_DropPoolId == itemData["itemModelId"] then
                rowInfo = v
            end
        end
        if rowInfo and rowInfo.f_Hero and rowInfo.f_Hero~= "" then
            isChangeToChips = true
        end
    end
    FireEvent(Config.EventType.Fresh_BagUseItemBack, isChangeToChips);
    FireEvent(Config.EventType.Fresh_Bag);
end

function ItemManager.useItemReturn()
    return tabUseBackItem;
end

function ItemManager.ParseRewards(json)
    local rewards = {}
    local reward = decodeJsonStrToTabel(json)
    if reward and table.getn(reward) > 0 then
        for k, v in pairs(reward) do
            local item = {}
            item.itemModelId = v[1]
            item.num = v[2]
            table.insert(rewards, item)
        end
    end
    return rewards
end

function ItemManager.updateSourceUI(obj, dataList, colseFun, goFun)
    if dataList == nil or #dataList <= 0 then
        return ;
    end
    this.sourceUI = {};
    this.sourceUI.obj = obj;
    this.sourceUI.text1 = obj:GetChild("text1");
    this.sourceUI.list = obj:GetChild("list");
    this.sourceUI.title = obj:GetChild("title");
    this.sourceUI.btnClose = obj:GetChild("btnClose");
    this.sourceUI.nothingController = obj:GetController("nothing");
    this.sourceUI.btnClose.onClick:Clear();
    this.sourceUI.btnClose.onClick:Add(function()
        if colseFun then
            colseFun();
        end
    end);
    this.sourceUI.data = {};
    local itemTableData;
    local goTableList;
    local sourceData;
    for k, v in pairs(dataList) do
        itemTableData = G.dataTable["t_item"][tostring(v)];
        if itemTableData ~= nil then
            goTableList = {};
            if itemTableData.f_source ~= "" then
                goTableList = decodeJsonStrToTabel(itemTableData.f_source);
                if logicMgr.MapManager.GetCurrentStage() < 532 then
                    table.sort(goTableList, function (a, b)
                        if a[2] == 0 or b[2] == 0 then return a[2] == 0; end
                        return a[2] > b[2];
                    end);
                else
                    table.sort(goTableList, function (a, b) return a[2] > b[2] end);
                end
                for key, value in pairs(goTableList) do
                    local data = {};
                    data.itemId = v;
                    sourceData = G.dataTable["t_source"][tostring(value[1])];
                    data.recommend = value[2];
                    data.state = 0;
                    if sourceData ~= nil then
                        if sourceData.f_type == 1 and logicMgr.ItemManager.getBagNumByTableID(sourceData.f_key) > 0 and not isOpenUI(PanelNames.UIBag) then
                            data.state = 1
                        elseif sourceData.f_type == 2 then
                            data.state = 1
                        end
                        if data.state >= 1 then
                            data.sourceId = value[1];
                            table.insert(this.sourceUI.data, data);
                        end
                  
                    end
                end
            else
                if colseFun then
                    colseFun();
                end
                return;
            end
        end
    end
    if #this.sourceUI.data > 0 then
        this.sourceUI.nothingController.selectedIndex = 0;
        this.sourceUI.list:RemoveChildrenToPool();
        for i = 1, #this.sourceUI.data do
            local item = this.sourceUI.list:AddItemFromPool();
            this.updateSourceItem(item, this.sourceUI.data[i], goFun);
        end
        this.sourceUI.list:ScrollToView(0);
    else
        this.sourceUI.nothingController.selectedIndex = 1;
        this.sourceUI.title.text = getLanguage("SourceTips4")
    end
end

function ItemManager.updateSourceItem(obj, data, goFun)
    this.sourceUI.itemUI = {};
    this.sourceUI.itemUI.title = obj:GetChild("title");
    this.sourceUI.itemUI.item = obj:GetChild("item");
    this.sourceUI.itemUI.tips = obj:GetChild("tips");
    this.sourceUI.itemUI.btn_Go = obj:GetChild("btn_Go");
    this.sourceUI.itemUI.isRecommendController = obj:GetController("ifRecommend");
    this.sourceUI.itemUI.isFunc = obj:GetController("ifFunc");
    this.sourceUI.itemUI.typeController = obj:GetController("type");
    this.sourceUI.itemUI.title.text = logicMgr.ItemManager.GetItemName(data.itemId);
    logicMgr.CostManager.RefreshItem(this.sourceUI.itemUI.item, {data.itemId});
    this.sourceUI.itemUI.btn_Go.onClick:Clear();
    if data.recommend == 0 then
        this.sourceUI.itemUI.isRecommendController.selectedIndex = 1;
    else
        this.sourceUI.itemUI.isRecommendController.selectedIndex = 0;
    end
    if data.sourceId == nil then
        this.sourceUI.itemUI.tips.text = getLanguage("SourceTips3");
    else
        this.sourceUI.itemUI.sourceData = G.dataTable["t_source"][tostring(data.sourceId)];
        if this.sourceUI.itemUI.sourceData == nil then
            this.sourceUI.itemUI.tips.text = getLanguage("SourceTips3");
            this.sourceUI.itemUI.btn_Go.onClick:Add(function()
                UISysTips.AddMsg(getLanguage("SourceTips3"));
            end);
        else
            local key = this.sourceUI.itemUI.sourceData.f_key;
            local isClose = this.sourceUI.itemUI.sourceData.f_close;
            if this.sourceUI.itemUI.sourceData.f_type == 1 then
                this.sourceUI.itemUI.typeController.selectedIndex = 0
                this.sourceUI.itemUI.btn_Go.onClick:Add(function()
                    if data.state >= 1 then
                        local _data = logicMgr.ItemManager.getItemConstDatabyModelId(key, true);
                        _data.itemId = logicMgr.ItemManager.getItemIdByModelId(key);
                        showUI(PanelNames.UIBagItemInfo, _data, 1);
                    else
                        UISysTips.AddMsg(getLanguage("SourceTips2"));
                    end
                end);
                this.sourceUI.itemUI.tips.text = string.format(getLanguage("SourceTips1", nil, "%s"),logicMgr.ItemManager.GetItemName(key));
            else
                this.sourceUI.itemUI.typeController.selectedIndex = 1
                if logicMgr.FuncOpenManager.isOpen(key) then
                    this.sourceUI.itemUI.isFunc.selectedIndex = 0;
                else
                    this.sourceUI.itemUI.isFunc.selectedIndex = 1;
                end
                this.sourceUI.itemUI.btn_Go.onClick:Add(function()
                    if key == Config.FuncOpenType.EquipShop then
                        if GuildManager.getUnionId() == 0 then
                            UISysTips.AddMsg(getLanguage("GuildInvestment_1114"));
                            return
                        end
                    end
                    if logicMgr.FuncOpenManager.isOpen(key, true, obj) then
                        if goFun and isClose ~= 1 then
                            goFun();
                        end
                        logicMgr.FuncOpenManager.jump(key, true);
                    end
                end);
                this.sourceUI.itemUI.tips.text = string.format(getLanguage("SourceTips1", nil, "%s"),getLanguage(this.sourceUI.itemUI.sourceData.f_FunctionName));
            end
        end
    end
end
function ItemManager.IsEquip(itemModelId)
    if not itemModelId then
        return false
    end
    local isEquip = this.getItemTabType(itemModelId) == EnumConst.ItemTableEnum.Equip
    return isEquip
end
function ItemManager.showGetItem(isChangeToChips)
    this.isChangeToChips = isChangeToChips
    logicMgr.HeroManager.showNewHero(this.showItem,TAManager.GetHeroSource.Bags);
end

function ItemManager.showItem()
    local tabItems = logicMgr.ItemManager.useItemReturn();
    if table.getn(tabItems) > 0 then
        showUI(PanelNames.UICommonItemGet,nil,nil,3,tabItems,nil,nil,nil,nil,nil,this.isChangeToChips)
        this.isChangeToChips = false
    end
end
function ItemManager.setSourceStart(id, start)
    if this.sourceStartList == nil then
        this.sourceStartList = {};
    end
    this.sourceStartList[id] = start;
end

function ItemManager.getSourceStart(id)
    if this.sourceStartList == nil then
        this.sourceStartList = {};
    end
    return this.sourceStartList[id];
end

function ItemManager.getAllItems()
    local ls = {}
    for k,v in pairs(tabAllItem) do
        table.insert(ls, v)
    end
    return ls
end

function ItemManager.getConstFavorItemDatas()
    if table.isNullOrEmpty(this.constFavorItemDatas)then
        this.constFavorItemDatas={}
        for i,v in pairs(itemCfg)do
            if v.f_BagType==EnumConst.ItemTypeEnum.FavorGift then
                local item=v
                local itemData = {}
                itemData["name"] = getLanguage(item.f_ItemName);
                itemData["itemType"] = item.f_BagType;
                itemData["quality"] = item.f_Quality;
                itemData["icon"] = item.f_Icon;
                itemData["desc"] = getLanguage(item.f_Desc);
                itemData["itemFunction"] = item.f_ItemFunction;
                itemData["itemModelId"] = item.f_itemModelId
                itemData["scriptId"] = item.f_ScriptId;
                itemData["cornerMark"] = item.f_CornerMark
                itemData["cornerMarkRight"] = item.f_CornerMarkRight
                itemData["num"]=0
                table.insert(this.constFavorItemDatas,itemData)
            end
        end
        table.sort(this.constFavorItemDatas,function(a,b)
            return a.quality<b.quality
        end)
    end
    return this.constFavorItemDatas
end

function ItemManager.GetNeedHeroListByData(data)
    if data == nil then
        return {};
    end
    local list = {};
    local curEquipData;
    local tempOwner = logicMgr.HeroManager.getOwnerHeroListReadOnly();
    for k, v in pairs(tempOwner) do
        if v.category == 0 and logicMgr.HeroManager.getHeroShowLevelByPartnerId(v.partnerId) > 1 then
            curEquipData = logicMgr.EquipManager.getHeroEquipList(v.partnerId, true);
            for key, value in pairs(curEquipData) do
                if value.quality + 1 == data.quality then
                    table.insert(list, v);
                    break;
                end
            end
        end
    end
    table.sort(list, logicMgr.HeroManager.sortHero);
    return list;
end

return ItemManager